package com.example.canal.conf;

import ch.qos.logback.core.db.dialect.MySQLDialect;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.canal.redis.util.JsonUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import javax.sql.DataSource;
import java.util.*;

/**
 * @author: qiyangong
 * @email: qiyangong@odianyun.com
 * @Date: 下午3:26-2020/6/17
 * @Last modified by:qiyangong
 */
@Configuration
@EnableConfigurationProperties(value = DatasourceCustomerProperties.class)
@MapperScan(basePackages = {"com.odianyun.sync.mapper"},sqlSessionFactoryRef = "sqlSession")
public class DatasourceConfigure {

    @Value("${spring.profiles.active}")
    private String profile;

    public final static String PROD = "prod";


    @Autowired
    private DatasourceCustomerProperties customerProperties;


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.write")
    public DataSource writeDataSource() {
        final HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(this.customerProperties.getWrite().getDriverClassName());
        dataSource.setJdbcUrl(this.customerProperties.getWrite().getJdbcUrl());
        dataSource.setPassword(this.customerProperties.getWrite().getPassword());
        dataSource.setUsername(this.customerProperties.getWrite().getUsername());
        return dataSource;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.read")
    public DataSource readDataSource() {
        final HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(this.customerProperties.getRead().getDriverClassName());
        dataSource.setJdbcUrl(this.customerProperties.getRead().getJdbcUrl());
        dataSource.setPassword(this.customerProperties.getRead().getPassword());
        dataSource.setUsername(this.customerProperties.getRead().getUsername());
        return dataSource;
    }

    @Bean
    public DataSource msRoutingDataSource(@Qualifier("writeDataSource") DataSource writeDataSource,
                                          @Qualifier("readDataSource") DataSource readDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>(2);
        targetDataSources.put("write", writeDataSource);
        targetDataSources.put("read", readDataSource);
        MsRoutingDataSource msRoutingDataSource = new MsRoutingDataSource();
        msRoutingDataSource.setDefaultTargetDataSource(writeDataSource);
        msRoutingDataSource.setTargetDataSources(targetDataSources);
        return msRoutingDataSource;
    }


    @Bean(name = "sqlSession")
    public MybatisSqlSessionFactoryBean mybatisSqlSession(@Qualifier("msRoutingDataSource") DataSource msRoutingDataSource) throws Exception {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        //MP 自己定义的配置类
        MybatisConfiguration configuration = new MybatisConfiguration();
        //是否开启延迟加载，默认是false
        configuration.setAggressiveLazyLoading(false);
        //查询缓存：myBatis一级缓存|二级缓存，默认开启
        configuration.setCacheEnabled(true);
        //指定当结果集中值为 null 的时候是否调用映射对象的 setter（map 对象时为 put）方法，
        // 这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型（int、boolean 等）是不能设置成 null 的。
        configuration.setCallSettersOnNulls(true);
        // 指定 MyBatis 应如何自动映射列到字段或属性。
        // NONE 表示关闭自动映射；PARTIAL 只会自动映射没有定义嵌套结果映射的字段。
        // FULL 会自动映射任何复杂的结果集（无论是否嵌套）。
        configuration.setAutoMappingBehavior(AutoMappingBehavior.PARTIAL);
        //允许 JDBC 支持自动生成主键，需要数据库驱动支持。
        // 如果设置为 true，将强制使用自动生成主键。尽管一些数据库驱动不支持此特性，但仍可正常工作（如 Derby）。
        configuration.setUseGeneratedKeys(true);
        //设置超时时间，它决定数据库驱动等待数据库响应的秒数。
        configuration.setDefaultStatementTimeout(10);
        configuration.setDefaultFetchSize(100);
        //当没有为参数指定特定的 JDBC 类型时，空值的默认 JDBC 类型。
        // 某些数据库驱动需要指定列的 JDBC 类型，多数情况直接用一般类型即可，比如 NULL、VARCHAR 或 OTHER。
        configuration.setJdbcTypeForNull(JdbcType.VARCHAR);
        configuration.addInterceptor(mybatisPlusInterceptor());
        //输出sql到日志实现 比如输出到console,file
        configuration.setLogImpl(StdOutImpl.class);
        bean.setConfiguration(configuration);
        bean.setDataSource(msRoutingDataSource);
        //设置数据库方言
        configuration.setDefaultSqlProviderType(MySQLDialect.class);
        bean.setTypeAliasesPackage("com.odianyun.sync.model");
        List<Resource> resources = new ArrayList<>();
        resources.addAll(Arrays.asList(resolver.getResources("classpath*:/mp/*Mapper.xml")));
        bean.setMapperLocations(resources.toArray(new Resource[resources.size()]));
        return bean;
    }

    /**
     * 乐观锁的拦截器 @version注解的字段值会自动递增
     * 分页插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }


    @Bean
    public RedisSerializer valueSerializer(RedisTemplate<Object, Object> redisTemplate) {
        ObjectMapper objectMapper = JsonUtils.MAPPER;
        GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
        redisTemplate.setValueSerializer(valueSerializer);
        redisTemplate.setHashValueSerializer(valueSerializer);
        return valueSerializer;
    }




}
